package com.xiaoshuidi.cloud.module.member.service.questionnaireinfo;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.framework.redis.lock.DistributeLock;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.module.contract.api.ContractApi;
import com.xiaoshuidi.cloud.module.contract.vo.ContractRoomReqVO;
import com.xiaoshuidi.cloud.module.member.constant.Constant;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.AnswerVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.OptionItem;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.OptionVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.PreviewQuestionnaireInfo;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionItem;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionnaireDetailVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionnaireExcelCountVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionnaireInfoCreateVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionnairePageRespVO;
import com.xiaoshuidi.cloud.module.member.controller.admin.questionnaireinfo.vo.QuestionnairePageVO;
import com.xiaoshuidi.cloud.module.member.controller.app.questionnaireinfo.vo.ParticipateVO;
import com.xiaoshuidi.cloud.module.member.controller.app.questionnaireinfo.vo.UserAnswerVO;
import com.xiaoshuidi.cloud.module.member.controller.app.questionnaireinfo.vo.UserQuestionVO;
import com.xiaoshuidi.cloud.module.member.controller.app.questionnaireinfo.vo.UserQuestionnaireVO;
import com.xiaoshuidi.cloud.module.member.enums.QuestionTypeEnum;
import com.xiaoshuidi.cloud.module.member.enums.SexEnum;
import com.xiaoshuidi.cloud.module.member.enums.point.PointRecordEnums;
import com.xiaoshuidi.cloud.module.member.mapper.questionnaireinfo.MemberQuestionnaireInfoMapper;
import com.xiaoshuidi.cloud.module.member.pojo.questionnaireinfo.MemberAnswer;
import com.xiaoshuidi.cloud.module.member.pojo.questionnaireinfo.MemberOption;
import com.xiaoshuidi.cloud.module.member.pojo.questionnaireinfo.MemberQuestion;
import com.xiaoshuidi.cloud.module.member.pojo.questionnaireinfo.MemberQuestionnaireApartment;
import com.xiaoshuidi.cloud.module.member.pojo.questionnaireinfo.MemberQuestionnaireInfo;
import com.xiaoshuidi.cloud.module.member.pojo.user.MemberUser;
import com.xiaoshuidi.cloud.module.member.repository.MemberAnswerRepository;
import com.xiaoshuidi.cloud.module.member.repository.MemberOptionRepository;
import com.xiaoshuidi.cloud.module.member.repository.MemberQuestionRepository;
import com.xiaoshuidi.cloud.module.member.repository.MemberQuestionnaireApartmentRepository;
import com.xiaoshuidi.cloud.module.member.repository.MemberQuestionnaireInfoRepository;
import com.xiaoshuidi.cloud.module.member.repository.MemberUserRepository;
import com.xiaoshuidi.cloud.module.member.service.point.MemberPointsService;
import com.xiaoshuidi.cloud.module.member.util.CodeUtil;
import com.xiaoshuidi.cloud.module.member.utils.DeepCopyUtils;
import com.xiaoshuidi.cloud.module.system.api.sms.SmsSendApi;
import com.xiaoshuidi.cloud.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.module.member.enums.ErrorCodeConstants.QUESTIONNAIRE_NOT_EXIST;
import static com.xiaoshuidi.cloud.module.member.enums.ErrorCodeConstants.QUESTIONNAIR_REPEAT_ANSWER;

@Slf4j
@Service
@RequiredArgsConstructor
public class MemberQuestionnaireInfoServiceImpl extends ServiceImpl<MemberQuestionnaireInfoMapper, MemberQuestionnaireInfo> implements MemberQuestionnaireInfoService {
    private final MemberQuestionnaireInfoRepository memberQuestionnaireInfoRepository;

    private final MemberQuestionRepository memberQuestionRepository;

    private final MemberOptionRepository memberOptionRepository;

    private final MemberAnswerRepository memberAnswerRepository;

    private final MemberPointsService memberPointsService;

    private final ContractApi contractApi;

    private final MemberUserRepository memberUserRepository;

    private final static String QUESTIONNAIRE_SMS_TEMPLATE = "questionnaire-sms-template";

    private final MemberQuestionnaireApartmentRepository memberQuestionnaireApartmentRepository;

    private final StringRedisTemplate redisTemplate;
    private final CodeUtil codeUtil;

    @Resource
    private SmsSendApi smsSendApi;

    @Value("${questionnaire.url}")
    private String questionnaireUrl;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long create(QuestionnaireInfoCreateVO createReqVO) {
        Long id = memberQuestionnaireInfoRepository.create(createReqVO);
        memberQuestionnaireApartmentRepository.insert(id, createReqVO.getApartmentIds());
        return id;
    }

    @Override
    public PageResult<QuestionnairePageRespVO> getPage(QuestionnairePageVO pageVO) {
        return memberQuestionnaireInfoRepository.getPage(pageVO);
    }

    @Override
    public QuestionnaireDetailVO getQuestionnaireById(Long id) {
        MemberQuestionnaireInfo byId = memberQuestionnaireInfoRepository.getById(id);
        QuestionnaireDetailVO vo = new QuestionnaireDetailVO();
        BeanUtils.copyProperties(byId, vo);
        //查看门店
        List<MemberQuestionnaireApartment> apartments = memberQuestionnaireApartmentRepository.getApartmentsByQuestionnaireId(id);
        if (apartments != null && apartments.size() > 0) {
            List<Long> apartmentIds = apartments.stream().map(MemberQuestionnaireApartment::getApartmentId).collect(Collectors.toList());
            vo.setApartmentIds(apartmentIds);
        }
        return vo;
    }

    @Override
    public PreviewQuestionnaireInfo previewQuestionnaire(Long id) {
        //查询问卷信息基本表
        PreviewQuestionnaireInfo info = new PreviewQuestionnaireInfo();
        MemberQuestionnaireInfo questionnaireInfo = memberQuestionnaireInfoRepository.getById(id);
        BeanUtils.copyProperties(questionnaireInfo, info);
        //查询问卷对应的所有题目
        List<MemberQuestion> questions = memberQuestionRepository.getQuestionsByQuestionnaireId(id);

        //查询问卷对应所有选项
        List<MemberOption> options = memberOptionRepository.getOptionsByQuestionnaireId(id);
        Map<String, List<MemberOption>> map = options.stream().collect(Collectors.groupingBy(o -> fetchKey(o.getQuestionnaireId(), o.getQuestionId())));

        //选项塞入相应的问题中
        List<QuestionItem> questionItems = questions.stream().map(q -> {
            QuestionItem questionItem = new QuestionItem();
            BeanUtils.copyProperties(q, questionItem);
            String fetchKey = fetchKey(q.getQuestionnaireId(), q.getId());
            List<MemberOption> memberOptions = map.get(fetchKey);
            if (memberOptions != null && memberOptions.size() > 0) {
                List<OptionItem> optionItems = memberOptions.stream().map(o -> {
                    OptionItem optionItem = new OptionItem();
                    BeanUtils.copyProperties(o, optionItem);
                    return optionItem;
                }).collect(Collectors.toList());
                questionItem.setOptionItems(optionItems);
            }
            return questionItem;
        }).collect(Collectors.toList());

        //题目塞入问卷中
        info.setQuestionItems(questionItems);
        Integer status = memberQuestionnaireInfoRepository.getStatus(questionnaireInfo);
        info.setQuestionnaireStatus(status);
        return info;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean answer(UserQuestionnaireVO vo) {
        if (StringUtils.isNotEmpty(vo.getKey()) & ObjectUtils.isEmpty(vo.getId())) {
            String value = redisTemplate.opsForValue().get(vo.getKey());
            HashMap map = JsonUtils.parseObject(value, HashMap.class);
            vo.setId(Long.parseLong(map.get("id").toString()));
            vo.setUserId(Long.parseLong(map.get("userId").toString()));
        } else {
            Long id = SecurityFrameworkUtils.getLoginUser().getId();
            vo.setUserId(id);
        }
        String key = Constant.POINT_ID_KEY.concat(vo.getUserId().toString());
        try (DistributeLock lock = DistributeLock.getLock(key)) {
            if (lock.tryLock()) {
                ParticipateVO participateVO = new ParticipateVO();
                participateVO.setUserId(vo.getUserId());
                participateVO.setId(vo.getId());
                Boolean flag = memberAnswerRepository.participateOrNot(participateVO);
                if (flag){
                    throw exception(QUESTIONNAIR_REPEAT_ANSWER);
                }
                List<MemberAnswer> answers = new ArrayList<>();
                List<UserQuestionVO> userQuestions = vo.getUserQuestions();
                for (UserQuestionVO userQuestion : userQuestions) {
                    List<UserAnswerVO> userAnswers = userQuestion.getUserAnswers();
                    for (UserAnswerVO userAnswer : userAnswers) {
                        MemberAnswer memberAnswer = new MemberAnswer();
                        memberAnswer.setQuestionnaireId(vo.getId());
                        memberAnswer.setQuestionId(userQuestion.getId());
                        memberAnswer.setOptionId(userAnswer.getOptionId());
                        memberAnswer.setName(userAnswer.getName());
                        memberAnswer.setContent(userAnswer.getContent());
                        memberAnswer.setFillBlank(userAnswer.getFillBlank());
                        memberAnswer.setImage(userAnswer.getImage());
                        if (ObjectUtils.isNotEmpty(vo.getUserId())) {
                            memberAnswer.setCreator(vo.getUserId().toString());
                            memberAnswer.setUpdater(vo.getUserId().toString());
                        }
                        answers.add(memberAnswer);
                    }
                }
                //批量插入用户答卷
                memberAnswerRepository.saveBatch(answers);
                //给用户送积分
                //1.查询到用户答题的积分
                MemberQuestionnaireInfo questionnaire = memberQuestionnaireInfoRepository.getById(vo.getId());
                try {

//            Long id = SecurityFrameworkUtils.getLoginUser().getId();
                    Long id = null;
                    if (ObjectUtils.isNotEmpty(vo.getUserId())) {
                        id = vo.getUserId();
                    } else {
                        id = SecurityFrameworkUtils.getLoginUser().getId();
                    }
                    memberPointsService.memberPointsChange(id, questionnaire.getBonusPoints(), PointRecordEnums.QUESTIONNAIRE, "用户参与问卷调查奖励积分");
                } catch (Exception e) {
                    log.error("用户参与问卷调查奖励积分异常", e.getMessage());
                }
                return true;
            }
        }
        return null;
    }

    @Override
    public List<QuestionVO> getQuestionList(Long questionnaireId) {
        List<QuestionVO> questionList = memberQuestionRepository.getQuestionList(questionnaireId);
        questionList.stream().peek(q -> q.setTypeName(ObjectUtils.isNotEmpty(q.getType()) ? QuestionTypeEnum.getNameByCode(q.getType()) : null))
                .collect(Collectors.toList());
        return questionList;
    }

    @Override
    public List<List<String>> getQuestionnaireData(Long questionnaireId) throws IOException, ClassNotFoundException {
        //获取此问卷所有参与者所选答案
        List<QuestionnaireExcelCountVO> data = memberQuestionRepository.getgetQuestionnaireData(questionnaireId);
        List<QuestionVO> questionList = getQuestionList(questionnaireId);
        data.stream().peek(d -> {
            //获取answerList
            List<AnswerVO> answerList = d.getAnswerList();
            //按照questionId分组
            Map<Long, List<AnswerVO>> collect = answerList.stream().collect(Collectors.groupingBy(AnswerVO::getQuestionId));
            d.setQuestionAnswerMap(collect);
        }).collect(Collectors.toList());
        List<List<String>> dataList = new ArrayList<>();

        for (int i = 1; i <= data.size(); i++) {
            //每个用户的一条记录
            List<String> list = new ArrayList<>();
            list.add(i + "");
            QuestionnaireExcelCountVO questionnaireExcelCountVO = data.get(i - 1);
            list.add(questionnaireExcelCountVO.getUserName());
            list.add(questionnaireExcelCountVO.getMobile());
            list.add(ObjectUtils.isNotEmpty(questionnaireExcelCountVO.getAge()) ? String.valueOf(questionnaireExcelCountVO.getAge()) : "");
            //获取门店信息todo
            try {
                CommonResult<ContractRoomReqVO> roomIdByApartment = contractApi.getRoomIdByApartment(questionnaireExcelCountVO.getUserId());
                if (ObjectUtils.isNotEmpty(roomIdByApartment)) {
                    ContractRoomReqVO contractRoomReqVO = roomIdByApartment.getData();
                    if (StringUtils.isNotEmpty(contractRoomReqVO.getApartmentName())) {
                        list.add(contractRoomReqVO.getApartmentName());
                    } else {
                        list.add("");
                    }
                } else {
                    list.add("");
                }
            } catch (Exception e) {
                log.error("获取用户最新合同签约门店失败");
                list.add("");
            }
            list.add(ObjectUtils.isNotEmpty(questionnaireExcelCountVO.getGender()) ? SexEnum.getNameByCode(questionnaireExcelCountVO.getGender()) : "");

            //对应入住时间
            try {
                CommonResult<Long> lengthOfStay = contractApi.getLengthOfStay(questionnaireExcelCountVO.getUserId());
                if (lengthOfStay.isSuccess()) {
                    Long month = lengthOfStay.getData();
                    list.add(month + "");
                } else {
                    list.add("");
                }
            } catch (Exception e) {
                log.error("获取租户入住月份失败:{}", e.getMessage());
                list.add("");
            }
            //对应的答案map
            Map<Long, List<AnswerVO>> questionAnswerMap = questionnaireExcelCountVO.getQuestionAnswerMap();
            for (int m = 1; m <= questionList.size(); m++) {
                QuestionVO questionVO = questionList.get(m - 1);
                List<OptionVO> optionList = DeepCopyUtils.deepCopy(questionVO.getOptionList());
                OptionVO option = new OptionVO();
                optionList.add(0, option);
                int optionSize = optionList.size();
                for (int n = 1; n <= optionSize; n++) {
                    OptionVO optionVO = optionList.get(n - 1);
                    if (ObjectUtils.isEmpty(optionVO.getId())) {
                        if (questionVO.getType().intValue() == QuestionTypeEnum.FILL_BLANKS.getCode().intValue()) {
                            //找到对应题目的填空答案
                            List<AnswerVO> answers = questionAnswerMap.get(questionVO.getId());
                            if (answers != null && answers.size() > 0) {
                                AnswerVO answerVO = answers.get(0);
                                list.add(StringUtils.isNotEmpty(answerVO.getFillBlank()) ? answerVO.getFillBlank() : "");
                            } else {
                                list.add("");
                            }
                        } else { //选项不是填空和画图题
                            list.add("");
                        }
//                        else if (questionVO.getType().intValue() == QuestionTypeEnum.PICTURE.getCode().intValue()) {
//                            //找到对应题目的填空答案
//                            List<AnswerVO> answers = questionAnswerMap.get(questionVO.getId());
//                            if (answers != null && answers.size() > 0) {
//                                AnswerVO answerVO = answers.get(0);
//                                list.add(answerVO.getImage());
//                            } else {
//                                list.add("");
//                            }
//                        }

                    } else {
                        if (questionVO.getType().intValue() == QuestionTypeEnum.SINGLE_CHOICE.getCode().intValue() ||
                                questionVO.getType().intValue() == QuestionTypeEnum.MULTIPLE_CHOICE.getCode().intValue() ||
                                questionVO.getType().intValue() == QuestionTypeEnum.PICTURE.getCode().intValue() ||
                                questionVO.getType().intValue() == QuestionTypeEnum.SINGLE_FILL_BLANK.getCode().intValue()) {
                            List<AnswerVO> answers = questionAnswerMap.get(questionVO.getId());
                            //如果选了答案，就填写name
                            if (containsOption(optionVO.getId(), answers)) {
                                AnswerVO answerFromList = getAnswerFromList(optionVO.getId(), answers);
                                list.add(answerFromList.getName() + (StringUtils.isEmpty(answerFromList.getFillBlank()) ? "" : ":" + answerFromList.getFillBlank()));
                            } else {
                                //如果选了答案，就填写""
                                list.add("");
                            }
                        } else { //如果不是那几种题型
                            list.add("");
                        }
                    }
                }
            }
            dataList.add(list);
        }

        return dataList;
    }

    @Override
    public Boolean participateOrNot(ParticipateVO participateVO) {
        return memberAnswerRepository.participateOrNot(participateVO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean publish(Long id) {
        memberQuestionnaireInfoRepository.savePublishTime(id);
        //发送问卷调查短信给租住人
        //1.查看门店信息

        try {
            MemberQuestionnaireInfo byId = memberQuestionnaireInfoRepository.getById(id);
            if (byId == null) {
                throw exception(QUESTIONNAIRE_NOT_EXIST);
            }
            //发送积分值
            Integer bonusPoints = byId.getBonusPoints();
            //查看是否发送短信
            if (byId.getSendMsg()) {
                //查询门店信息
                List<MemberQuestionnaireApartment> apartments = memberQuestionnaireApartmentRepository.getApartmentsByQuestionnaireId(id);
                log.info("问卷门店信息{}", JsonUtils.toJsonString(apartments));
                if (apartments != null && apartments.size() > 0) {
                    List<Long> apartmentIds = apartments.stream().map(MemberQuestionnaireApartment::getApartmentId).collect(Collectors.toList());
                    CommonResult<List<Long>> result = contractApi.getMemberIdsByApartmentIds(apartmentIds);
                    log.info("根据门店查询用户id信息{}", JsonUtils.toJsonString(result));
                    if (result.isSuccess()) {
                        List<Long> data = result.getData();
                        if (data != null && data.size() > 0) {
                            List<MemberUser> users = memberUserRepository.listByIds(data);
                            log.info("发送短信给用户信息{}", JsonUtils.toJsonString(users));
                            for (MemberUser user : users) {
                                //发送短信
                                SmsSendSingleToUserReqDTO reqDTO = new SmsSendSingleToUserReqDTO();
                                reqDTO.setMobile(user.getMobile());
                                reqDTO.setTemplateCode(QUESTIONNAIRE_SMS_TEMPLATE);
                                reqDTO.setUserId(user.getId());
                                Set<String> shortUrlParamName = new HashSet<>();
                                shortUrlParamName.add("url");
                                reqDTO.setShortUrlParamName(shortUrlParamName);
                                Map<String, Object> templateParams = new HashMap<>();
                                //1.把问卷id和用户id存入redis
                                HashMap<String, Object> redisMap = new HashMap<>();
                                redisMap.put("id", id);
                                redisMap.put("userId", user.getId());
                                String key = codeUtil.nextCode("CO");
                                redisTemplate.opsForValue().set(key, JsonUtils.toJsonString(redisMap));
                                StringBuffer sb = new StringBuffer();
                                sb.append(questionnaireUrl).append("?key=").append(key);
                                templateParams.put("url", sb.toString());
                                templateParams.put("point", bonusPoints);
                                reqDTO.setTemplateParams(templateParams);
                                log.info("发送短信接口数据{}", JsonUtils.toJsonString(reqDTO));
                                smsSendApi.sendSingleSmsToMember(reqDTO);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("发送短信失败", e);
            throw new RuntimeException(e);
        }

        return true;
    }

    @Override
    public Boolean update(QuestionnaireInfoCreateVO vo) {
        memberQuestionnaireInfoRepository.update(vo);
        if (vo.getApartmentIds() != null && vo.getApartmentIds().size() > 0) {
            memberQuestionnaireApartmentRepository.updateApartment(vo.getId(), vo.getApartmentIds());
        }

        return true;
    }

    @Override
    public Boolean otherParticipateOrNot(String key) {
        String value = redisTemplate.opsForValue().get(key);
        HashMap map = JsonUtils.parseObject(value, HashMap.class);
        ParticipateVO participateVO = new ParticipateVO();
        participateVO.setId(Long.parseLong(map.get("id").toString()));
        participateVO.setUserId(Long.parseLong(map.get("userId").toString()));
        return this.participateOrNot(participateVO);
    }

    @Override
    public PreviewQuestionnaireInfo otherPreviewQuestionnaire(String key) {
        String value = redisTemplate.opsForValue().get(key);
        HashMap map = JsonUtils.parseObject(value, HashMap.class);
        return this.previewQuestionnaire(Long.parseLong(map.get("id").toString()));
    }

    /**
     * 答案是否选了此选项
     *
     * @param optionId
     * @param answers
     * @return
     */
    private boolean containsOption(Long optionId, List<AnswerVO> answers) {
        for (AnswerVO answer : answers) {
            if (answer.getOptionId().intValue() == optionId) {
                return true;
            }
        }
        return false;
    }

    public AnswerVO getAnswerFromList(Long optionId, List<AnswerVO> answers) {
        for (AnswerVO answer : answers) {
            if (answer.getOptionId().intValue() == optionId) {
                return answer;
            }
        }
        return null;
    }

    private String fetchKey(Long questionnaireId, Long questionId) {
        return questionnaireId + "_" + questionId;
    }
}
